<?php
namespace app\kefuswoole;

use app\kefu\model\KfChatLog as KfChatLogModel;
use app\kefu\model\KfUser as KfUserModel;
use app\kefu\model\KfGuestTrace as KfGuestTraceModel;
use app\kefu\model\kfServiceLog as kfServiceLogModel;
use think\facade\Cache;

class Event
{

    public static function userInit($server, $fd, $data)
    {
        $redis = Cache::store('redis');
        $shop_id = $data['shop_id']; //店铺
        array_key_exists("uid", $data) && self::guestConnect($server, $fd, $data); //用户
        array_key_exists("fid", $data) && self::kfConnect($server, $fd, $data); //客服
    }
    public static function kfConnect($server, $fd, $data)
    {
        echo "kf {$data['fid']} connect".PHP_EOL;
        $redis = Cache::store('redis');
        $shop_id = $data['shop_id'];
        $code = $data['code'];
        //基本信息 chat_user_info_[uid] {userinfo}
        $kfinfo = [
            'id' => $data['fid'],
            'name' => $data['name'],
            'avatar' => $data['avatar'],
            'code' => $data['code'],
            'shop_id' => $shop_id,
        ];
        $server->bind($fd, crc32($kfinfo['id']));
        //基本信息 chat_user_info_[uid] {userinfo}
        $redis->set("chat_kf_info_uid:{$code}_fd:{$fd}", $kfinfo);
        //存用户 chat_k1f_sid:[shop_id]_fd:[fd]_uid:[user_id] {userinfo} 在线列表
        $redis->set("chat_k1f_sid:{$shop_id}_fd:{$fd}_uid:{$code}", $kfinfo);
        //存fd chat_k2f_sid:[shop_id]_uid:[user_id]_fd:[fd] {fd} 通讯FD
        $redis->set("chat_k2f_sid:{$shop_id}_uid:{$code}_fd:{$fd}", $fd);

        //店铺客服列表
        $redis->sadd("shop_{$shop_id}_kf_fd", $fd);

        //对话列表 chat_u1f_sid:{$shop_id}_uid:*_kid:{$fid}_fd:[fd]
        $keys = $redis->keys("chat_u1f_sid:{$shop_id}_uid:*_kid:{$code}_fd:*");
        $info = [];
        foreach ($keys as $k => $v) {
            $info[] = $redis->get($v);
        }
        //通知用户
        $_fd = $redis->sMembers("shop_{$shop_id}_user_fd");
        foreach ($_fd as $link) {
         
            try {
                $server->push($link, self::response('onlineDiff', $kfinfo));
            } catch (\Throwable $th) {
                $redis->sismember("shop_{$shop_id}_user_fd", $fd);
            }
        }
        //取在线用户列表
        return $server->push($fd, self::response('get_user_info', $info));
    }
    /**
     * 访客初始化
     * @param $message
     * @param $client_id
     */
    public static function guestConnect($server, $fd, $data)
    {
        echo "guest {$data['uid']} connect".PHP_EOL;
        $redis = Cache::store('redis');
        $shop_id = $data['shop_id'];
        //基本信息 chat_user_info_[uid] {userinfo}
        $userinfo = [
            'name' => $data['name'],
            'avatar' => $data['avatar'],
            'code' => $data['uid'],
            'shop_id' => $shop_id,
        ];
        $redis->set("chat_user_info_uid:{$userinfo['code']}_fd:{$fd}", $userinfo);
        //店铺用户列表
        $redis->sadd("shop_{$shop_id}_user_fd", $fd);
        $server->bind($fd, crc32($userinfo['code']));

        //尝试分配一个客服
        $kf_info = KfUserModel::field('password', true)
            ->where(['status' => 1, 'shop_id' => $shop_id])
            ->order(['online'=>'DESC','sort'=>'DESC','service_num'=>'ASC'])
            ->find();

        if ($kf_info) {
            $_kf_info = [
                'name' => $kf_info['username'],
                'code' => $kf_info['code'],
                'avatar' => $kf_info['avatar'],
                'shop_id' => $shop_id,
            ];
            //存用户 chat_u1f_sid:[shop_id]_uid:[user_id][kf_id]_fd:[fd] {userinfo} 在线列表
            $redis->set("chat_u1f_sid:{$shop_id}_uid:{$data['uid']}_kid:{$kf_info['code']}_fd:{$fd}", $userinfo);
            //存fd chat_u2f_sid:[shop_id]_uid:[user_id]_kid:[kf_id]_fd:[fd] {fd} 通讯FD
            $redis->set("chat_u2f_sid:{$shop_id}_uid:{$data['uid']}_kid:{$kf_info['code']}_fd:{$fd}", $fd);
            $taskData = [];
            $taskData['fd']=$fd;
            $taskData['data']['type']='serviceLog';
            $taskData['data']['kf'] = $_kf_info;
            $taskData['data']['guest'] = $userinfo;
            $res = self::response('kf_link', $_kf_info);
            $server->task(json_encode($taskData), 0);
        } else {
            $res = self::response('kf_busy', '客服忙,请稍候再试.');
        }

        //发给游客 安排了 客服
        $server->push($fd, $res);

        //发给客服 准备接客啦

        //通知客服
        $keys = $redis->keys("chat_k2f_sid:{$shop_id}_uid:{$kf_info['code']}_*");
        $_fd = [];
        foreach ($keys as $k => $v) {
            $_fd[] = $redis->get($v);
        }
        foreach ($_fd as $link) {
            $msg = [
                'code'=>$userinfo['code']
                ,'name'=>$userinfo['name']
                ,'avatar'=>$userinfo['avatar']
                ,'shop_id' => $shop_id
            ];
            try {
                $server->push($link, self::response('guest_link', $msg));
            } catch (\Throwable $th) {
                $redis->del($redis->keys("chat_k2f_sid:{$shop_id}_uid:{$kf_info['code']}_fd:{$link}"));
            }
        }
        return;
    }
    /**
     * 处理聊天信息
     * @param [wsobj] $server
     * @param [frame->fd] $fd
     * @param [array] $data
     * @return void
     */
    public static function chatMessage($server, $fd, $data)
    {
        $redis = Cache::store('redis');
        //获取to_fd
        $to = $data['to'];
        $from = $data['mine'];
        $source = $to['source'];
        $shop_id = $to['shop_id'];
 
        if ('kf' == $source) {
            echo "chatMessage k->u chat_u2f_sid:{$shop_id}_uid:{$to['code']}_kid:{$from['code']}_*" . PHP_EOL;
            //接收FD
            $keys = $redis->keys("chat_u2f_sid:{$shop_id}_uid:{$to['code']}_kid:{$from['code']}_*");
            $_fd = [];
            foreach ($keys as $k => $v) {
                $_fd[] = $redis->get($v);
            }
        } else {
            echo "chatMessage u->k chat_k2f_sid:{$shop_id}_uid:{$to['code']}_*" . PHP_EOL;
            //接收FD
            $keys = $redis->keys("chat_k2f_sid:{$shop_id}_uid:{$to['code']}_*");
            $_fd = [];
            foreach ($keys as $k => $v) {
                $_fd[] = $redis->get($v);
            }
        }
        
        $fd_json = json_encode($_fd);
        echo "chatMessage bath fd:{$fd_json}\n";
        //多设备发送
        $from['content'] = $to['content'];
        unset($to['content']);
        foreach ($_fd as $k => $link) {
            $msg = ['to'=>$from,'mine'=>$to];
            $server->push($link, self::response('chatMessage', $msg));
        }
        unset($addData, $_fd);
    }
    /**
     * 断开连接
     * @param $fd  客户端标识
     * @param $data  请求数据
     */
    public static function disconnect($server, $fd)
    {

        $redis = Cache::store('redis');
        $_userinfo = $redis->get(current($redis->keys("chat_user_info_uid:*_fd:{$fd}")));
        if ($_userinfo) {
            return self::userClose($server, $fd, $_userinfo);
        }
        $_kfinfo = $redis->get(current($redis->keys("chat_kf_info_uid:*_fd:{$fd}")));
        if ($_kfinfo) {
            //存客服下线状态
            KfUserModel::where(['code'=>$_kfinfo['code']])->update(['online'=>0]);
            return self::kfClose($server, $fd, $_kfinfo);
        }

        echo "disconnect from fd:{$fd} uid\n";
        return true;
    }
    /**
     * 用户退出
     *
     * @param [type] $server
     * @param [type] $fd
     * @param [type] $data
     * @return void
     */
    public static function userClose($server, $fd, $data)
    {
        $redis = Cache::store('redis');
        $_shop_ids = $_key = [];
        //查找FD所在店铺
        $_key = (array) $redis->keys("shop_*_user_fd");
        foreach ($_key as $k => $v) {
            if ($redis->sismember($v, $fd)) {
                echo "{$fd} in {$v}\n";
                $_shop_ids[] = explode('_', $v)[1];
                $redis->srem($v, $fd);
            }
        }
        //通知所有店铺客服
        foreach ($_shop_ids as $k => $v) {
            $_fd = $redis->sMembers("shop_{$v}_kf_fd");
            foreach ($_fd as $link) {
                $msg = ['from_fd' => $fd, 'to_fd' => $link, 'code' => $data['code']];
                try {
                    $server->push($link, self::response('closeDiff', $msg));
                } catch (\Throwable $th) {
                    $redis->sismember("shop_{$v}_kf_fd", $fd);
                }

            }
        }
        $redis->del($redis->keys("*fd:{$fd}*"));
        $redis->del($redis->keys("*uid:{$data['code']}*"));
    }
    /**
     * 客服退出
     *
     * @param [type] $server
     * @param [type] $fd
     * @param [type] $data
     * @return void
     */
    public static function kfClose($server, $fd, $data)
    {
        $redis = Cache::store('redis');
        $_shop_ids = $_key = [];
        //查找FD所在店铺
        $_key = (array) $redis->keys("shop_*_kf_fd");
        foreach ($_key as $k => $v) {
            if ($redis->sismember($v, $fd)) {
                echo "{$fd} in {$v}\n";
                $_shop_ids[] = explode('_', $v)[1];
                $redis->srem($v, $fd);
            }
        }
        //通知所有店铺用户
        foreach ($_shop_ids as $k => $v) {
            $_fd = $redis->sMembers("shop_{$v}_user_fd");
            foreach ($_fd as $link) {
                $msg = ['from_fd' => $fd, 'to_fd' => $link, 'code' =>  $data['code']];
                try {
                    $server->push($link, self::response('closeDiff', $msg));
                } catch (\Throwable $th) {
                    $redis->sismember("shop_{$v}_user_fd", $fd);
                }
            }
        }
        $redis->del($redis->keys("*fd:{$fd}*"));
        $redis->del($redis->keys("*uid:{$data['code']}*"));
    }
    /**
     * 组装返回数据
     * @param $type 信息类别
     * @param $data 返回数据
     * @param int $code 返回状态码
     * @param string $msg 返回状态信息
     * @return string 转换的json数据
     */
    public static function response($type, $data, $code = 200, $msg = '请求成功')
    {
        $result = [
            'code' => $code,
            'msg' => $msg,
            'message_type' => $type,
            'data' => $data,
        ];
        return json_encode($result, JSON_UNESCAPED_UNICODE);
    }
    /**
     * 队列数据库操作
     *
     * @param [type] $data
     * @return void
     */
    public static function addChatHistory($data){
        $data = json_decode($data,true);
        $fd    = $data['fd'];   //通讯FD
        $param = $data['data']; //参数
        $type  = $param['type'];//动作
        switch ($type) {
            case 'onOpen':
                //用户上线
                if(@array_key_exists("uid", $param)){
                    $param['source'] = 'guest';
                    KfGuestTraceModel::addTrace($fd,$param);
                }
                //客服上线
                if(@array_key_exists("fid", $param)){
                    $param['source'] = 'kf';
                    KfUserModel::where(['code'=>$param['code']])->update(['online'=>1]);
                }
                break;
            case 'serviceLog':
                    //服务记录
                    kfServiceLogModel::addTrace($fd,$param);
                    break;
            case 'chatMessage':
                    //服务记录
                    KfChatLogModel::addData($fd,$param);
                    break;
            case 'onClose':
                    //关闭连接
                    kfServiceLogModel::updateTrace($fd,$param);
                    break;
            default:
                # code...
                break;
        }
    }
    //状态维护
    public static function statFd($server){
        echo date('Y-m-d H:i:s').'维护FD状态'.PHP_EOL;
        $fds=[];
        foreach($server->connections as $fd){
            array_push($fds,$fd);
        }
        kfServiceLogModel::statFd($fds);
    }
}
